package com.ccp.dev.workflow.controller;

import com.ccp.dev.core.basic.annotion.Action;
import com.ccp.dev.core.basic.consts.SystemConst;
import com.ccp.dev.core.basic.consts.UrlConstants;
import com.ccp.dev.core.basic.internationalization.SysBaseController;
import com.ccp.dev.core.basic.model.SysAuditModelType;
import com.ccp.dev.core.basic.response.ResultData;
import com.ccp.dev.core.basic.table.TableModel;
import com.ccp.dev.core.basic.util.ContextUtil;
import com.ccp.dev.core.basic.util.PropertyUtil;
import com.ccp.dev.core.basic.web.query.QueryFilter;
import com.ccp.dev.core.jms.IMessageHandler;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.RequestUtil;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.core.util.log.SysAuditThreadLocalHolder;
import com.ccp.dev.form.model.FormDef;
import com.ccp.dev.form.service.FormDefService;
import com.ccp.dev.form.service.FormRightsService;
import com.ccp.dev.form.service.FormTableService;
import com.ccp.dev.form.util.PlatformType;
import com.ccp.dev.system.dao.SysUserDao;
import com.ccp.dev.system.model.*;
import com.ccp.dev.system.service.SysFileService;
import com.ccp.dev.system.util.SysRoleUtil;
import com.ccp.dev.workflow.bpmconst.BpmConst;
import com.ccp.dev.workflow.bpmutil.BpmUtil;
import com.ccp.dev.workflow.bpmutil.ServiceUtil;
import com.ccp.dev.workflow.dao.ActDefModelDao;
import com.ccp.dev.workflow.dao.TaskHistoryDao;
import com.ccp.dev.workflow.model.*;
import com.ccp.dev.workflow.model.bpm.*;
import com.ccp.dev.workflow.service.*;
import com.ccp.dev.workflow.service.bpm.BpmNodeSignService;
import com.ccp.dev.workflow.service.bpm.BpmRunLogService;
import com.ccp.dev.workflow.service.bpm.TaskSignDataService;
import com.ccp.dev.workflow.service.bpm.impl.BpmFlowableService;
import com.ccp.dev.workflow.service.bpm.thread.MessageUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

/**
 * ClassDescribe:流程任务管理控制类
 * @author :fanyanyan
 * Date: 2019-07-10
 */
@RequestMapping(UrlConstants.PROJECT_ROOT + UrlConstants.PROJECT_MODULE_WORKFLOW + "/task")
@Controller
@Action(ownermodel = SysAuditModelType.PROCESS_CENTER)
public class TaskController extends SysBaseController {
    private static final String SUCCESS = "operation.success";
    private static final String FAILURE = "operation.failure";

    @Resource
    private BpmService bpmService;
    @Resource
    private ProcessRunService processRunService;
    @Resource
    private TaskReadService taskReadService;
    @Resource
    private ActDefModelDao actDefModelDao;
    @Resource
    private TaskService taskService;
    @Resource
    private BpmNodeButtonService bpmNodeButtonService;
    @Resource
    private BpmFormRunService bpmFormRunService;
    @Resource
    private ActDefModelService actDefModelService;
    @Resource
    private BpmDefAuthorizeService bpmDefAuthorizeService;
    @Resource
    private BpmNodeSetService bpmNodeSetService;
    @Resource
    private FormHandlerService formHandlerService;
    @Resource
    private BpmRunLogService bpmRunLogService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private BpmNodeUserService bpmNodeUserService;
    @Resource
    private BpmTaskExeService bpmTaskExeService;
    @Resource
    private FormDefService formDefService;
    @Resource
    private CommuReceiverService commuReceiverService;
    @Resource
    private TaskOpinionService taskOpinionService;
    @Resource
    private TaskUserService taskUserService;
    @Resource
    private TaskSignDataService taskSignDataService;
    @Resource
    private BpmNodeSignService bpmNodeSignService;
    @Resource
    private TaskApprovalItemsService taskApprovalItemsService;
    @Resource
    private SysFileService sysFileService;
    @Resource
    private TaskReminderService reminderService;
    @Resource
    private BpmFlowableService bpmFlowableService;
    @Resource
    private SysUserDao sysUserDao;
    @Resource
    private TaskHistoryDao taskHistoryDao;
    @Resource
    private FormRightsService formRightsService;

    /**
     * 新建流程跳转
     * @return 返回结果路径
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX + "/newProcess")
    @Action(description = "查看新建流程页面")
    public String viewProcessList() {
        return getAutoView();
    }

    /**
     * 流程补签
     * @param request request
     * @return ResultData
     */
    @RequestMapping("/addSign")
    @ResponseBody
    @Action(description = "流程会签补签",detail = "流程会签补签<#if fl>成功<#else>失败</#if>")
    public ResultData addSign(HttpServletRequest request) {
        String taskId = request.getParameter("taskId");
        String signUserIds = request.getParameter("signUserIds");
        String opinion = request.getParameter("opinion");
        String informType = RequestUtil.getString(request, "informType");
        if (StringUtil.isNotEmpty(taskId) && StringUtil.isNotEmpty(signUserIds) && StringUtil.isNotEmpty(opinion)) {
            // 保存意见
            try {
                taskSignDataService.addSign(signUserIds, taskId, opinion, informType);
            } catch (Exception e) {
                e.printStackTrace();
                SysAuditThreadLocalHolder.putParamerter("fl", false);
                return getResultDataError("operation.failure");
            }
        }
        SysAuditThreadLocalHolder.putParamerter("fl", true);
        return getResultDataSuccess("operation.success");
    }

    /**
     * 查询新建流程列表
     * @param request request
     * @return Object
     */
    @RequestMapping(UrlConstants.MODULE_FUNCTION_LIST + "/newProcess")
    @Action(description = "查询有启动权限的流程数据列表",detail = "查询有启动权限的流程数据列表<#if fl>成功<#else>失败</#if>")
    @ResponseBody
    public Object newProcessList(HttpServletRequest request) {
        try {
            QueryFilter queryFilter = new QueryFilter(request, true);
            String userId = ContextUtil.getCurrentUserId();
            queryFilter.put("userId", userId);

            // 增加流程分管授权查询判断
            String isNeedRight = "";
            if (!ContextUtil.isSuperAdmin()) {
                isNeedRight = "yes";
                Map<String, Object> actRightMap = bpmDefAuthorizeService.getActRightsByUserMap(userId,
                        BpmDefAuthorizeType.BPMDEFAUTHORIZE_RIGHT_TYPE.START, false, false);
                // 获取流程分管授权与用户相关的信息集合的流程key
                String actRights = (String) actRightMap.get("authorizeIds");
                queryFilter.addFilter("actRights", actRights);
            }
            queryFilter.addFilter("isNeedRight", isNeedRight);

            // 查询流程列表
            List<ActDefModel> list = actDefModelService.queryNewProcessList(queryFilter);
            SysAuditThreadLocalHolder.putParamerter("fl", true);
            return getResultDataSuccess("operation.success", queryFilter.getPageBean().getTotalCount(), list);
        }catch (Exception e){
            SysAuditThreadLocalHolder.putParamerter("fl", false);
            return getResultDataError("operation.failure");
        }

    }

    /**
     * 流程任务管理页面
     *
     * @return 页面路径
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX + UrlConstants.MODULE_FUNCTION_LIST)
    @Action(ownermodel = SysAuditModelType.PROCESS_MANAGEMENT, description = "查看流程任务管理页面")
    public String viewList(Model model) {
        SysUser curUser = (SysUser) ContextUtil.getCurrentUser();
        model.addAttribute("privacyLevel", curUser.getPrivacyLevel());
        return getAutoView();
    }

    /**
     * 流程任务数据列表
     * @param request request
     * @return Object
     */
    @RequestMapping(UrlConstants.MODULE_FUNCTION_LIST)
    @Action(ownermodel = SysAuditModelType.PROCESS_MANAGEMENT,description = "查询流程任务数据列表",detail = "查询流程任务数据列表<#if fl>成功<#else>失败</#if>")
    @ResponseBody
    public Object list(HttpServletRequest request) {

        try {
            QueryFilter queryFilter = new QueryFilter(request, true);
            String userId = ContextUtil.getCurrentUserId();
            queryFilter.addFilter("userId", userId);
            // 增加按新的流程分管授权中任务类型的权限获取流程的任务
            String isNeedRight = "";

            if (!ContextUtil.isSuperAdmin()) {
                isNeedRight = "yes";
                // 获得流程分管授权与用户相关的信息
                Map<String, Object> actRightMap = bpmDefAuthorizeService.getActRightsByUserMap(userId, BpmDefAuthorizeType.BPMDEFAUTHORIZE_RIGHT_TYPE.TASK, false, false);

                // 获得流程分管授权与用户相关的信息集合的流程KEY
                String actRights = (String) actRightMap.get("authorizeIds");
                queryFilter.addFilter("actRights", actRights);
            }
            queryFilter.addFilter("isNeedRight", isNeedRight);

            List<ProcessTask> list = bpmService.getTasks(queryFilter);

            request.getSession().setAttribute("isAdmin", true);
            SysAuditThreadLocalHolder.putParamerter("fl", true);
            return getResultDataSuccess(SUCCESS, queryFilter.getPageBean().getTotalCount(), list);
        } catch (Exception e) {
            SysAuditThreadLocalHolder.putParamerter("fl", false);
            return getResultDataError(FAILURE,1,e.getMessage());
        }

    }

    /**
     * 任务处理界面，根据任务ID获取流程实例，根据流程实例获取表单数据。
     * @param request request
     * @param model 视图模型对象
     * @return 页面路径
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX + "/toStart")
    @Action(description = "任务处理页面")
    public String toStart(HttpServletRequest request, Model model){
        return getToStartView(request, model, 0);
    }

    /**
     * 启动任务界面。 根据任务ID获取流程实例，根据流程实例获取表单数据
     * @param request request
     * @param model 视图模型对象
     * @return ModelAndView
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX + "/doNext")
    @Action(ownermodel = SysAuditModelType.PROCESS_MANAGEMENT,description = "流程任务管理-任务处理页面")
    public ModelAndView doNext(HttpServletRequest request, Model model){
        String view = getToStartView(request, model, 1);
        return new ModelAndView(view.replace("doNext","toStart"),model.asMap());
    }


    /**
     * 任务处理页面
     * @param request request
     * @param model 视图模型对象
     * @param isManage 是否管理员，0：非管理员；1：管理员
     * @return 页面路径
     */
    private String getToStartView(HttpServletRequest request, Model model, int isManage) {
        try {
            SysUser sysUser = (SysUser) ContextUtil.getCurrentUser();
            String taskId = RequestUtil.getString(request, "taskId");
            String procInstId = RequestUtil.getString(request, "instanceId");
            String runId = RequestUtil.getString(request, "runId");
            //2020-03-09 jyq添加，是否是在线任务交接处单击事项名称访问的
            String handover = RequestUtil.getString(request, "handover");
            if (StringUtil.isEmpty(taskId) && StringUtil.isEmpty(procInstId)) {
                return ServiceUtil.getTipInfo(model, "没有输入任务或实例ID!");
            }
            // 根据流程实例获取流程任务。
            if (StringUtil.isEmpty(taskId) && StringUtil.isNotEmpty(procInstId)) {
                List<ProcessTask> list = bpmService.getTasks(procInstId);
                if (BeanUtils.isNotEmpty(list)) {
                    taskId = list.get(0).getId();
                }
            }
            // 查找任务节点
            TaskEntity taskEntity = bpmService.getTask(taskId);
            if (taskEntity == null) {
                ProcessTaskHistory taskHistory = taskHistoryDao.getById(taskId);
                if (taskHistory == null) {
                    if (StringUtil.isEmpty(taskId) && StringUtil.isEmpty(procInstId)) {
                        return ServiceUtil.getTipInfo(model, "任务ID错误!");
                    }
                } else {
                    String processInstanceId = taskHistory.getProcessInstanceId();
                    if (StringUtil.isEmpty(processInstanceId) && taskHistory.getDescription().equals(TaskOpinion.STATUS_COMMUNICATION.toString())) {
                        return ServiceUtil.getTipInfo(model, "此任务为沟通任务,并且此任务已经处理!");
                    }
                    ProcessRun processRun = processRunService.getByProcInstanceId(processInstanceId);
                    if (processRun == null) {
                        return ServiceUtil.getTipInfo(model, "任务不存在!");
                    }
                    String url = "/workflow/processRun/view/info?runId=" + processRun.getRunId();
                    return "redirect:" + url;
                }
                return null;
            }
            if (StringUtil.isEmpty(handover) && TaskOpinion.STATUS_TRANSTO_ING.toString().equals(taskEntity.getDescription()) && taskEntity.getAssignee().equals(sysUser.getUserId())) {
                return ServiceUtil.getTipInfo(model, "对不起,这个任务正在流转中,不能处理此任务!");
            }
            procInstId = taskEntity.getProcessInstanceId();

            if (isManage == 0) {
                boolean hasRights = processRunService.getHasRightsByTask(taskEntity.getId(), sysUser.getUserId());
                if (!hasRights) {
                    return ServiceUtil.getTipInfo(model, "对不起,你不是这个任务的执行人,不能处理此任务!");
                }
            }
            // 更新任务为已读。
            taskReadService.saveReadRecord(procInstId, taskId);
            // 设置沟通人员或流转人员查看状态。
            commuReceiverService.setCommuReceiverStatus(taskEntity, sysUser);

            String nodeId = taskEntity.getTaskDefinitionKey();
            String procDefId = taskEntity.getProcessDefinitionId();
            String userId = ContextUtil.getCurrentUserId();

            ActDefModel actDefModel = actDefModelDao.getByProcDefId(procDefId);
            ProcessRun processRun = processRunService.getByProcInstanceId(procInstId);
            String businessKey = processRun.getBusinessKey();
            boolean isFirstNode = NodeCache.isFirstNode(procDefId, nodeId);
            BpmNodeSet bpmNodeSet;
            String parentProcDefId = "";
            int dataPrivacyLevel = 1;
            Map<String, Object> variables = taskService.getVariables(taskId);
            if (variables.containsKey(BpmConst.FLOW_PARENT_PROCDEFID)) {
                // 判断当前是否属于子流程任务
                parentProcDefId = variables.get(BpmConst.FLOW_PARENT_PROCDEFID).toString();
                bpmNodeSet = bpmNodeSetService.getByProcDefIdNodeId(procDefId, nodeId, parentProcDefId);
            } else {
                bpmNodeSet = bpmNodeSetService.getByProcDefIdNodeId(procDefId, nodeId);
            }

            String toBackNodeId = "";
            if (StringUtil.isNotEmpty(processRun.getStartNode())) {
                toBackNodeId = processRun.getStartNode();
            } else {
                try {
                    toBackNodeId = NodeCache.getFirstNodeInfo(procDefId).getNodeId();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            String form = "";
            String tempLaunchId = userId;
            if (StringUtil.isEmpty(taskEntity.getExecutionId())) {
                if (taskEntity.getDescription().equals(TaskOpinion.STATUS_TRANSTO.toString())) {
                    List<TaskOpinion> taskOpinionList = taskOpinionService.getByProcInstId(procInstId);
                    if (BeanUtils.isNotEmpty(taskOpinionList)) {
                        TaskOpinion taskOpinion = taskOpinionList.get(taskOpinionList.size() - 1);
                        List<CommuReceiver> commuReceiverList = commuReceiverService.getByOpinionId(taskOpinion.getOpinionId());
                        if (BeanUtils.isNotEmpty(commuReceiverList)) {
                            tempLaunchId = taskOpinion.getExeUserId();
                        }
                    }
                }
            }

            int formType = bpmNodeSet.getFormType();
            //是否绑定表单
            Boolean isFormEmpty = formType == -1;
            //是否外部表单
            Boolean isExtForm = formType > 0;

            if (isExtForm) {
                //外部表单
                form = bpmNodeSet.getFormUrl().replaceFirst(BpmConst.FORM_PK_REGEX, businessKey);

            } else if (formType == 0) {
                //在线表单
                form = "/form/dataTemplate/view/addEdit?formKey=" + bpmNodeSet.getFormKey() + "&id=" + processRun.getBusinessKey() + "&procDefId=" + procDefId + "&nodeId=" + nodeId + "&hideBtn=yes" + "&needHeadAndBottom=no&enableEditPrivacy=0";
                // 获取密级传回前台.
                if (StringUtil.isNotEmpty(processRun.getBusinessKey())&& StringUtil.isNotEmpty(processRun.getDsAlias())) {
                    dataPrivacyLevel = formHandlerService.getPrivacyLevelByTable(processRun.getDsAlias(), processRun.getTableName(), processRun.getPkName(), processRun.getBusinessKey());
                }
            }
            // 是否会签任务
            boolean isSignTask = NodeCache.isSignTaskNode(procDefId, nodeId);
            if (isSignTask) {
                handleSignTask(model, procInstId, nodeId, procDefId, userId);
            }
            // 是否支持回退
            boolean isCanBack = false;
            //2019-11-07    新增判断，解决因为沟通任务可能不存在执行人ID（executionId）而导致页面错误500
            if (StringUtil.isNotEmpty(taskEntity.getExecutionId())) {
                isCanBack = bpmFlowableService.isTaskAllowBack(taskId);
            }
            // 是否转办
            boolean isCanAssignee;
            isCanAssignee = bpmTaskExeService.isAssigneeTask(taskEntity, actDefModel);

            // 是否隐藏路径
            boolean isHidePath = getIsHidePath(bpmNodeSet.getIsHidePath());

            // 是否是选择路径跳转
            boolean isHandChoose = false;
            if (!isHidePath) {
                boolean canChoicePath = bpmService.getCanChoicePath(procDefId, taskId);
                String curUserId = ContextUtil.getCurrentUserId();
                List<NodeTranUser> nodeTranUserList = bpmService.getNodeTaskUserMap(taskId, curUserId, canChoicePath);
                if (nodeTranUserList.size() > 1) {
                    isHandChoose = true;
                }
            }

            // 获取页面显示的按钮
            Map<String, List<BpmNodeButton>> mapButton = bpmNodeButtonService.getMapByDefNodeId(procDefId, nodeId);

            //获取消息通知类型
            Map handlersMap = ServiceUtil.getHandlerMap();
            //获取常用语
            List<String> taskAppItems = taskApprovalItemsService.getApprovalByDefKeyAndTypeId(actDefModel.getModelKey(), actDefModel.getTypeId());
            // 获取保存的意见
            TaskOpinion taskOpinion = taskOpinionService.getOpinionByTaskIdUserId(taskId, userId);
            // 帮助文档
            SysFile sysFile = null;
            if (BeanUtils.isNotEmpty(actDefModel.getAttachment())) {
                sysFile = sysFileService.getOneById(actDefModel.getAttachment());
            }
            // 是否有全局流水号
            boolean hasGlobalFlowNo = PropertyUtil.getBooleanByAlias(SysProperty.GLOBAL_FLOW_NO);
            model.addAttribute("task", taskEntity)
                    .addAttribute("runId", runId)
                    .addAttribute("procInstId", procInstId)
                    .addAttribute("taskId", taskId)
                    .addAttribute("bpmNodeSet", bpmNodeSet)
                    .addAttribute("processRun", processRun)
                    .addAttribute("actDefModel", actDefModel)
                    .addAttribute("isSignTask", isSignTask)
                    .addAttribute("toBackNodeId", toBackNodeId)
                    .addAttribute("isCanBack", isCanBack)
                    .addAttribute("isCanAssignee", isCanAssignee)
                    .addAttribute("isHidePath", isHidePath)
                    .addAttribute("mapButton", mapButton)
                    .addAttribute("isManage", isManage)
                    .addAttribute("isHandChoose", isHandChoose)
                    .addAttribute("handlersMap", handlersMap)
                    .addAttribute("curUserId", sysUser.getUserId())
                    .addAttribute("curUserName", sysUser.getFullName())
                    .addAttribute("formKey", bpmNodeSet.getFormKey())
                    .addAttribute("nodeId", nodeId)
                    .addAttribute("form", form)
                    .addAttribute("procDefId", procDefId)
                    .addAttribute("parentProcDefId", parentProcDefId)
                    .addAttribute("isExtForm", isExtForm)
                    .addAttribute("isFormEmpty", isFormEmpty)
                    .addAttribute("taskOpinion", taskOpinion)
                    .addAttribute("sysFile", sysFile)
                    .addAttribute("hasGlobalFlowNo", hasGlobalFlowNo)
                    .addAttribute("taskAppItems", taskAppItems)
                    .addAttribute("dataPrivacyLevel", dataPrivacyLevel)
                    .addAttribute("isFirstNode", isFirstNode)
                    .addAttribute("handover", handover);
            return getAutoView();
        } catch (Exception e) {
            model.addAttribute("content", e.getCause());
            return "workflow/task/tipInfo";
        }
    }

    /**
     * 处理会签
     * @param model mvc对象
     * @param procInstId 流程实例id
     * @param nodeId 节点id
     * @param procDefId 流程定义id
     * @param userId 用户id
     */
    private void handleSignTask(Model model, String procInstId, String nodeId, String procDefId, String userId) {
        List<TaskSignData> signDataList = taskSignDataService.queryByNodeAndInstanceId(procInstId, nodeId);
        // 获取会签规则
        BpmNodeSign bpmNodeSign = bpmNodeSignService.getByProcDefIdAndNodeId(procDefId, nodeId);

        model.addAttribute("signDataList", signDataList);
        model.addAttribute("bpmNodeSign", bpmNodeSign);
        model.addAttribute("curUser", ContextUtil.getCurrentUser());

        // 获取当前组织id
        String orgId = ContextUtil.getCurrentOrgId();

        // "允许直接处理"特权
        boolean isAllowDirectExecute = bpmNodeSignService.checkNodeSignPrivilege(procDefId, nodeId, BpmNodeSignService.BpmNodePrivilegeType.ALL_DIRECT, userId, orgId);
        // "允许补签"特权
        boolean isAllowRetoactive = bpmNodeSignService.checkNodeSignPrivilege(procDefId, nodeId, BpmNodeSignService.BpmNodePrivilegeType.ALLOW_RETROACTIVE, userId, orgId);
        // "一票决断"特权
        boolean isAllowOneVote = bpmNodeSignService.checkNodeSignPrivilege(procDefId, nodeId, BpmNodeSignService.BpmNodePrivilegeType.ALLOW_ONE_VOTE, userId, orgId);
        model.addAttribute("isAllowDirectExecute", isAllowDirectExecute).addAttribute("isAllowRetoactive", isAllowRetoactive)
                .addAttribute("isAllowOneVote", isAllowOneVote);
    }

    /**
     * 是否执行隐藏路径
     * @param isHidePath 是否隐藏路径
     * @return boolean
     */
    private boolean getIsHidePath(Short isHidePath) {
        if (BeanUtils.isEmpty(isHidePath)) {
            return false;
        }
        if (BpmNodeSet.HIDE_PATH.shortValue() == isHidePath.shortValue()) {
            return true;
        }
        return false;
    }

    /**
     * 获取页面参数
     * @param request request
     * @return Map
     */
    private Map getPageParam(HttpServletRequest request) {
        Map paraMap = RequestUtil.getParameterValueMap(request, false, false);
        paraMap.remove("businessKey");
        paraMap.remove("modelId");
        return paraMap;
    }

    /**
     * 任务审批
     * @param request request
     * @return ResultData
     */
    @RequestMapping("/complete")
    @Action(description = "任务审批",detail = "任务审批<#if fl>成功<#else>失败</#if>")
    @ResponseBody
    public Object complete(HttpServletRequest request) {
        SysAuditThreadLocalHolder.putParamerter("fl", false);
        SysUser curUser = (SysUser) ContextUtil.getCurrentUser();
        //获取任务id
        String taskId = RequestUtil.getString(request, "taskId");
        //获取任务
        TaskEntity task = bpmService.getTask(taskId);
        if (task == null) {
            return getResultDataError("task.is.finished");
        }
        String procDefId = task.getProcessDefinitionId();
        ActDefModel actDefModel = actDefModelDao.getByProcDefId(procDefId);
        if (ActDefModel.STATUS_INST_DISABLED.equals(actDefModel.getStatus())) {
            return getResultDataError("instance.isEnable");
        }
        String userId = curUser.getUserId();
        //从request获取数据组装cmd对象
        ProcessCmd taskCmd = BpmUtil.getProcessCmd(request);
        taskCmd.setCurrentUserId(userId);
        String assignee = task.getAssignee();
        // 非管理员,并且没有任务的权限。
        boolean isAdmin = taskCmd.getIsManage().shortValue() == 1;
        if (!isAdmin) {
            boolean rtn = processRunService.getHasRightsByTask(taskId, userId);
            if (!rtn) {
                return getResultDataError("task.has.noRight");
            }
        }

        // 记录日志。
        if (ServiceUtil.isAssigneeNotEmpty(assignee) && !task.getAssignee().equals(userId) && !isAdmin) {
            return getResultDataError("task.is.locked");
        } else {
            try {
                processRunService.nextProcess(taskCmd);
                SysAuditThreadLocalHolder.putParamerter("fl", true);
                return getResultDataSuccess("task.complete.success");
            } catch (Exception e) {
                e.printStackTrace();
                String msg = MessageUtil.getMessage();
                return getResultDataError(FAILURE,1,msg);
            }
        }
    }

    /**
     * 代办事宜
     * @param model 视图模型对象
     * @return 页面路径
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX + "/pendingMatters")
    @Action(description = "代办事宜页面")
    public String pendingMattersView(Model model) {
        String warningSet = reminderService.getWaringSetJson();
        model.addAttribute("warningSet",warningSet);
        return getAutoView();
    }

    /**
     * 待办任务列表
     * @param request request
     * @return Object
     */
    @RequestMapping(UrlConstants.MODULE_FUNCTION_LIST + "/pendingMatters")
    @Action(description = "查询待办任务数据列表",detail = "查询待办任务数据列表<#if fl>成功<#else>失败</#if>")
    @ResponseBody
    public Object pendingMattersList(HttpServletRequest request) {
        QueryFilter queryFilter = new QueryFilter(request, true);
        if(StringUtil.isNotEmpty(ContextUtil.getCurrentUserId()) && !SystemConst.SUPER_ADMIN_ID.equals(ContextUtil.getCurrentUserId())){
            SysRole currentSysRole = SysRoleUtil.getCurrentRole(request);
            if(null!=currentSysRole){
                queryFilter.addFilter("switchRoleId", currentSysRole.getRoleId());
            }
        }
        queryFilter.addFilter("typeId", RequestUtil.getString(request,"typeId"));
        try{
            List<ProcessTask> list = bpmService.queryMyTask(queryFilter);
            SysAuditThreadLocalHolder.putParamerter("fl", true);
            return getResultDataSuccess("operation.success", queryFilter.getPageBean().getTotalCount(), list);
        }catch(Exception e){
            SysAuditThreadLocalHolder.putParamerter("fl", false);
            return getResultDataError("operation.failure");
        }
    }


    /**
     * 启动流程页面
     * @param request request
     * @param model 视图模型对象
     * @return 页面路径
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX + "/startFlowForm")
    @Action(description = "启动流程页面")
    public String viewStartFlowForm(HttpServletRequest request, Model model) {
        try {
            String businessKey = RequestUtil.getString(request, "businessKey");
            // 复制表单 启动流程
            String copyKey = RequestUtil.getString(request, "copyKey", "");
            String modelId = RequestUtil.getString(request, "modelId");
            SysUser sysUser = (SysUser) ContextUtil.getCurrentUser();
            String tenantId = ContextUtil.getCurrentUserTenantId();
            // 流程草稿传入
            String runId = RequestUtil.getString(request, "runId");
            // 从已经完成的流程实例启动流程。
            String relRunId = RequestUtil.getString(request, "relRunId");
            // 构建参数到页面。
            Map paraMap = getPageParam(request);
            ProcessRun processRun = null;
            ActDefModel actDefModel = null;
            if (StringUtil.isNotEmpty(businessKey) && StringUtil.isEmpty(runId)) {
                processRun = processRunService.getByBusinessKey(businessKey);
                modelId = processRun.getModelId();
                runId = processRun.getRunId();
            }

            if (StringUtil.isNotEmpty(runId)) {
                processRun = processRunService.getById(runId);
                modelId = processRun.getModelId();
            }
            if (StringUtil.isNotEmpty(modelId)) {
                //验证流程的状态
                actDefModel = actDefModelService.getOneById(modelId);
                processRunService.checkBpmDefValid(actDefModel);
            }
            // 根据已经完成的流程实例取得业务主键。
            String pk = processRunService.getBusinessKeyByRelRunId(relRunId);
            if (StringUtil.isNotEmpty(businessKey)) {
                businessKey = pk;
            }
            //是否绑定表单
            Boolean isFormEmpty = false;
            //是否外部表单
            Boolean isExtForm = false;
            String form = "";
            String procDefId;
            // 通过草稿启动流程
            if (BeanUtils.isNotEmpty(processRun) && processRun.getStatus().equals(ProcessRun.STATUS_FORM)) {
                model.addAttribute("isDraft", true);
                businessKey = processRun.getBusinessKey();
                String formDefId = processRun.getFormDefId();
                procDefId = processRun.getProcDefId();
                BpmNodeSet bpmNodeSet = bpmFormRunService.getStartBpmNodeSet(procDefId);
                int isNewVersion = RequestUtil.getInt(request, "isNewVersion", 0);

                if (StringUtil.isNotEmpty(formDefId)) {
                    String tableName = processRun.getTableName();
                    if (!tableName.startsWith(TableModel.CUSTOMER_TABLE_PREFIX)) {
                        tableName = TableModel.CUSTOMER_TABLE_PREFIX + tableName;
                    }
                    boolean isExistsData = formHandlerService.isExistsData(processRun.getDsAlias(), tableName, processRun.getPkName(), processRun.getBusinessKey());
                    if (!isExistsData) {
                        return "redirect:/platform/bpm/task/noData.ht";
                    }
                }
                //url表单
                if (StringUtil.isNotEmpty(processRun.getBusinessUrl())) {
                    isExtForm = true;
                    form = processRun.getBusinessUrl();
                    // 替换主键。
                    form = form.replaceFirst(BpmConst.FORM_PK_REGEX, businessKey);
                } else {
                    if (isNewVersion == 1) {
                        FormDef defaultFormDef = formDefService.getOneById(formDefId);
                        formDefId = formDefService.getDefaultPublishedByFormKey(defaultFormDef.getFormKey()).getFormDefId();
                    }
                    FormDef formDef = formDefService.getOneById(formDefId);
                    form = "/form/dataTemplate/view/addEdit?formKey=" + formDef.getFormKey() + "&id=" + processRun.getBusinessKey() + "&procDefId=" + procDefId +"&nodeId="+bpmNodeSet.getNodeId()+ "&hideBtn=yes" + "&needHeadAndBottom=no";

                }
            } else {
                // 流程定义里面的启动
                if (StringUtil.isNotEmpty(copyKey)) {
                    businessKey = copyKey;
                }
                model.addAttribute("isDraft", false);
                procDefId = actDefModel.getProcDefId();
                // 获取表单节点
                BpmNodeSet bpmNodeSet = bpmFormRunService.getStartBpmNodeSet(procDefId);
                if (BeanUtils.isEmpty(bpmNodeSet)) {
                    throw new RuntimeException("该流程还没有绑定表单");
                }
                FormDef formDef = formDefService.getDefaultPublishedByFormKey(bpmNodeSet.getFormKey());
                // 是外部表单
                int formType = bpmNodeSet.getFormType();
                isFormEmpty = formType == -1;
                isExtForm = formType > 0;

                if (isExtForm) {
                    //外部表单
                    form = bpmNodeSet.getFormUrl().replaceFirst(BpmConst.FORM_PK_REGEX, businessKey);

                } else if (formType == 0) {
                    // 获取密级传回前台
                    //在线表单
                    form = "/form/dataTemplate/view/addEdit?formKey=" + formDef.getFormKey() + "&id="+businessKey + "&procDefId=" + procDefId+"&nodeId="+bpmNodeSet.getNodeId() + "&hideBtn=yes" + "&needHeadAndBottom=no";
                    model.addAttribute("formKey", bpmNodeSet.getFormKey());
                }
            }
            // 获取按钮
            Map<String, List<BpmNodeButton>> mapButton = bpmNodeButtonService.getMapByStartForm(procDefId);

            // 帮助文档
            SysFile sysFile = null;
            if(BeanUtils.isNotEmpty(actDefModel.getAttachment())){
                sysFile = sysFileService.getOneById(actDefModel.getAttachment());
            }

            if (NodeCache.isMultipleFirstNode(procDefId)) {
                model.addAttribute("flowNodeList", NodeCache.getFirstNodeList(procDefId)).addAttribute("isMultipleFirstNode", true);
            }

            model.addAttribute("actDefModel", actDefModel)
                    .addAttribute("isExtForm", isExtForm)
                    .addAttribute("isFormEmpty", isFormEmpty)
                    .addAttribute("mapButton", mapButton)
                    .addAttribute("modelId", modelId)
                    .addAttribute("paraMap", paraMap)
                    .addAttribute("form", form)
                    .addAttribute("runId", runId)
                    .addAttribute("curUserId", sysUser.getUserId())
                    .addAttribute("curUserName", sysUser.getFullName())
                    .addAttribute("businessKey", StringUtil.isEmpty(copyKey) ? businessKey : "")
                    .addAttribute("tenantId", tenantId)
                    .addAttribute("sysFile", sysFile);
            return getAutoView();
        } catch (Exception e) {
            model.addAttribute("content", e.getMessage());
            return "workflow/task/tipInfo";
        }
    }

    /**
     * 启动流程
     * @param request request
     * @return ResultData
     */
    @PostMapping(value = "/startFlow")
    @ResponseBody
    @Action(description = "启动流程", detail = "启动流程<#if fl>成功<#else>失败</#if>")
    public ResultData startFlow(HttpServletRequest request) {
        String runId = RequestUtil.getString(request, "runId");
        //指定执行人
        String nodeUserAssignee = StringEscapeUtils.unescapeHtml4(RequestUtil.getString(request, BpmConst.NODE_USER_ASSIGNEE));
        try {
            ProcessCmd processCmd = BpmUtil.getProcessCmd(request);
            processCmd.addVariable(BpmConst.NODE_USER_ASSIGNEE, nodeUserAssignee);
            String userId = ContextUtil.getCurrentUserId();
            processCmd.setCurrentUserId(userId);
            if (StringUtil.isNotEmpty(runId)) {
                ProcessRun processRun = processRunService.getById(runId);
                if (BeanUtils.isEmpty(processRun)) {
                    return getResultDataError("processRun.notExist");
                }
                processCmd.setProcessRun(processRun);
            }
            //启动流程
            processRunService.startProcess(processCmd);
            SysAuditThreadLocalHolder.putParamerter("fl", true);
            return getResultDataSuccess("run.success");
        } catch (Exception ex) {
            ex.printStackTrace();
            String message = MessageUtil.getMessage();
            SysAuditThreadLocalHolder.putParamerter("fl", false);
            return getResultDataError("run.failure",1,message);
        }
    }

    /**
     * 保存草稿
     * @param request request
     * @return Object
     */
    @RequestMapping("/saveDraft")
    @Action(description = "保存草稿数据", detail = "保存草稿数据<#if fl>成功<#else>失败</#if>")
    @ResponseBody
    public Object saveDraft(HttpServletRequest request){
        ProcessCmd processCmd = BpmUtil.getProcessCmd(request);
        String userId = ContextUtil.getCurrentUserId();
        processCmd.setCurrentUserId(userId);
        try {
            processRunService.saveDraft(processCmd);
            SysAuditThreadLocalHolder.putParamerter("fl", true);
            return getResultDataSuccess("save.success");
        } catch (Exception e) {
            SysAuditThreadLocalHolder.putParamerter("fl", false);
            return getResultDataError("save.failure");
        }
    }

    /**
     * 保存表单数据
     * @param request request
     * @return ResultData
     */
    @RequestMapping("/saveFlowData")
    @Action(description = "保存表单数据", detail = "保存表单数据<#if fl>成功<#else>失败</#if>")
    @ResponseBody
    public ResultData saveFlowData(HttpServletRequest request){
        ProcessCmd processCmd = BpmUtil.getProcessCmd(request);
        String userId = ContextUtil.getCurrentUserId();
        String runId  = RequestUtil.getString(request,"reRunId");
        if(StringUtil.isNotEmpty(runId)){
            ProcessRun processRun = processRunService.getById(runId);
            processCmd.setProcessRun(processRun);
        }
        processCmd.setCurrentUserId(userId);
        try{
            processRunService.saveFlowData(processCmd);
            SysAuditThreadLocalHolder.putParamerter("fl", true);
            return getResultDataSuccess("save.flow.success");
        }catch (Exception ex){
            ex.printStackTrace();
            SysAuditThreadLocalHolder.putParamerter("fl", false);
            return getResultDataError("save.flow.failure",1,ex.getMessage());
        }
    }

    /**
     * 获取授权后的流程分类
     * hasRoot：是否有根节点。1,有根节点;0,无根节点。
     * @param request request
     * @return ResultData
     */
    @RequestMapping("/processType" + UrlConstants.MODULE_FUNCTION_LIST)
    @ResponseBody
    public ResultData getAuthorizedProcessType(HttpServletRequest request) {
        String catKey = RequestUtil.getString(request, "catKey");
        boolean hasRoot = RequestUtil.getInt(request, "hasRoot", 1) == 1;
        List<GlobalType> list = processRunService.getAuthorizedProcessType(catKey, hasRoot);
        return success(list);
    }

    /**
     * 返回目标节点及其节点的处理人员映射列表
     * @param request request
     * @param model 视图模型对象
     * @return 页面路径
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX+"/tranTaskUserMap")
    public String viewTranTaskUserMap(HttpServletRequest request, Model model) {
        try {
            //是否启动流程
            int isStart = RequestUtil.getInt(request, "isStart", 0);
            String taskId = request.getParameter("taskId");
            String procDefId = request.getParameter("procDefId");
            String scope = "";
            if (StringUtil.isEmpty(taskId)) {
                List<FlowNodeInfo> firstNode = NodeCache.getFirstNodeList(procDefId);
                if (BeanUtils.isNotEmpty(firstNode)) {
                    FlowNodeInfo flowNode = firstNode.get(0);
                    String nodeId = flowNode.getNodeId();
                    BpmNodeSet bpmNodeSet = bpmNodeSetService.getByProcDefIdNodeIdOrParentProcDefId(nodeId, procDefId, "");
                    if (BeanUtils.isNotEmpty(bpmNodeSet)) {
                        scope = bpmNodeSet.getScope();
                    }
                }
            } else {
                // 获取当前节点的选择器限定配置
                ExecutionEntity execution;
                TaskEntity taskEntity = bpmService.getTask(taskId);
                // 加签任务
                if (TaskOpinion.STATUS_TRANSTO.toString().equals(taskEntity.getDescription())) {
                    // 获取它的parentTaskId，这里是放着的加签任务生成的源任务
                    execution = bpmService.getExecutionByTaskId_TransTo(taskEntity.getParentTaskId());
                } else if (TaskOpinion.STATUS_TRANSTO_ING.toString().equals(taskEntity.getDescription()) && StringUtil.isNotEmpty(taskEntity.getParentTaskId())) {
                    // 2020-02-26 jyq添加，存在多次流转的情况时，走该分支
                    execution = bpmService.getExecutionByTaskId_TransTo(taskEntity.getParentTaskId());
                } else {
                    execution = bpmService.getExecutionByTaskId(taskId);
                }

                String superExecutionId = execution.getSuperExecutionId();
                String parentProcDefId = "";
                if (StringUtil.isNotEmpty(superExecutionId)) {
                    ExecutionEntity supExecution = bpmService.getExecution(superExecutionId);
                    parentProcDefId = supExecution.getProcessDefinitionId();
                }
                String nodeId = execution.getActivityId();
                String processDefinitionId = execution.getProcessDefinitionId();
                BpmNodeSet bpmNodeSet = bpmNodeSetService.getByProcDefIdNodeIdOrParentProcDefId(nodeId, processDefinitionId, parentProcDefId);
                if (BeanUtils.isNotEmpty(bpmNodeSet)) {
                    scope = bpmNodeSet.getScope();
                }
            }
            //是否选择路径跳转
            int selectPath = RequestUtil.getInt(request, "selectPath", 1);
            boolean canChoicePath = bpmService.getCanChoicePath(procDefId, taskId);
            String startUserId = ContextUtil.getCurrentUserId();
            List<NodeTranUser> nodeTranUserList;
            if (isStart == 1) {
                //启动流程
                Map<String, Object> vars = new HashMap<>(15);
                Enumeration paramEnums = request.getParameterNames();
                String[] vnames;
                while(paramEnums.hasMoreElements()) {
                    String val;
                    String paramName = (String)paramEnums.nextElement();
                    //变量
                    if (paramName.startsWith("v_")) {
                        vnames = paramName.split("[_]");
                        if (vnames != null && vnames.length == 2) {
                            String varName = vnames[1];
                            val = request.getParameter(paramName);
                            if (!val.isEmpty()) {
                                vars.put(varName, val);
                            }
                        }
                    }
                }
                nodeTranUserList = bpmService.getStartNodeUserMap(procDefId, startUserId, vars);
            } else {
                nodeTranUserList = bpmService.getNodeTaskUserMap(taskId, startUserId, canChoicePath);
            }
            model.addAttribute("nodeTranUserList", nodeTranUserList).addAttribute("selectPath", selectPath).addAttribute("scope", scope).addAttribute("canChoicePath", canChoicePath);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return getAutoView();
    }

    /**
     * 任务自由跳转窗口显示
     * @param request request
     * @param model 视图模型对象
     * @return 页面路径
     */
    @RequestMapping("/freeJump")
    public String freeJump(HttpServletRequest request, Model model) {
        String taskId = RequestUtil.getString(request, "taskId");
        // 获取当前节点的选择器限定配置
        ExecutionEntity execution = bpmService.getExecutionByTaskId(taskId);
        String superExecutionId = execution.getSuperExecutionId();
        String parentProcDefId = "";
        if (StringUtil.isNotEmpty(superExecutionId)) {
            ExecutionEntity supExecution = bpmService.getExecution(superExecutionId);
            parentProcDefId = supExecution.getProcessDefinitionId();
        }
        String nodeId = execution.getActivityId();
        String processDefinitionId = execution.getProcessDefinitionId();
        BpmNodeSet bpmNodeSet = bpmNodeSetService.getByProcDefIdNodeIdOrParentProcDefId(nodeId, processDefinitionId, parentProcDefId);
        String scope = bpmNodeSet.getScope();

        Map<String, Map<String, String>> jumpNodesMap = bpmService.getJumpNodes(taskId);
        model.addAttribute("jumpNodeMap", jumpNodesMap).addAttribute("scope", scope);
        return getAutoView();
    }

    /**
     * 跳转节点选择页面
     * @param request http请求
     * @param model 视图容器
     * @return
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX + "/freeBack")
    public String viewFreeBack(HttpServletRequest request, Model model){
        String taskId = RequestUtil.getString(request, "taskId");
        model.addAttribute("taskId", taskId);
        return getAutoView();
    }

    /**
     * 跳转节点选择流程图
     * @param request
     * @param model
     * @return
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX + "/freeBackByFlowImg")
    public String viewFreeBackImg(HttpServletRequest request, Model model) {
        String taskId = RequestUtil.getString(request, "taskId");
        String procInstId = RequestUtil.getString(request, "procInstId");
        String runId = RequestUtil.getString(request, "runId");

        ProcessRun processRun ;
        if (StringUtils.isNotEmpty(runId)) {
            //bpm_pro_run
            processRun = processRunService.getById(runId);
            procInstId  = processRun.getProcInstId();
        }
        //获取流程实例
        else{
            processRun= processRunService.getByProcInstanceId(procInstId);
        }

        if(processRun==null){
            processRun= processRunService.getByProcInstanceIdFromHis(procInstId);
        }
        //将流程实例返回给页面
        model.addAttribute("procDefId", processRun.getProcDefId());
        model.addAttribute("subject", processRun.getSubject());
        //流程实例id返回给页面
        model.addAttribute("taskId", taskId);
        model.addAttribute("procInstId", procInstId);
        return getAutoView();
    }

    /**
     * 任务自由回退节点选择
     * @param request 请求
     * @return 结果封装
     */
    @RequestMapping("/freeBackNodes")
    @ResponseBody
    public ResultData freeBackNodes(HttpServletRequest request) {
        String taskId = RequestUtil.getString(request, "taskId");
        // 获取当前节点的选择器限定配置
        ExecutionEntity execution = bpmService.getExecutionByTaskId(taskId);
        String nodeId = execution.getActivityId();
        String processDefinitionId = execution.getProcessDefinitionId();
        Set<ActNode> preNodes = bpmService.getPreNodes(processDefinitionId, nodeId);
        return getResultDataSuccess("operation.success", preNodes.size(), preNodes);
    }

    /**
     * 检测任务是否存在
     * @param request request
     * @return ResultData
     */
    @RequestMapping("isTaskExsit")
    @ResponseBody
    public ResultData isTaskExsit(HttpServletRequest request){
        String taskId = RequestUtil.getString(request, "taskId");
        TaskEntity taskEnt = bpmService.getTask(taskId);
        if (taskEnt == null) {
            return ResultData.error("此任务已经完成!");
        } else {
            return ResultData.success("任务存在!");
        }
    }

    /**
     * 终止弹窗
     * 根据任务结束流程实例界面跳转。
     * @param request request
     * @param model 视图模型
     * @return ResultData
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX + "/endProcess")
    @Action(ownermodel = SysAuditModelType.PROCESS_MANAGEMENT,description = "终止任务页面")
    public String endProcess(HttpServletRequest request, Model model) {
        String taskId = request.getParameter("taskId");
        model.addAttribute("taskId", taskId);
        return getAutoView();
    }

    /**
     * 终止按钮,结束流程实例
     * @param request request
     * @return ResultData
     */
    @RequestMapping("endProcess")
    @Action(ownermodel = SysAuditModelType.PROCESS_MANAGEMENT,description = "终止任务<#if fl>成功<#else>失败</#if>")
    @ResponseBody
    public ResultData endProcess(HttpServletRequest request){
        String taskId = RequestUtil.getString(request, "taskId");
        String memo = RequestUtil.getString(request, "memo");
        TaskEntity taskEnt = bpmService.getTask(taskId);
        if (taskEnt == null) {
            return getResultDataError("task.already.finished");
        }
        String instanceId = taskEnt.getProcessInstanceId();
        try {
            String nodeId = taskEnt.getTaskDefinitionKey();
            bpmService.endProcessByInstanceId(instanceId, nodeId, memo);
            SysAuditThreadLocalHolder.putParamerter("fl", true);
            return getResultDataSuccess("process.end.success");
        } catch (Exception ex) {
            ex.printStackTrace();
            SysAuditThreadLocalHolder.putParamerter("fl", false);
            return getResultDataError("operation.failure");
        }


    }

    /**
     * 获取某个流程实例上某个节点的配置执行人员
     * @param request request
     * @return ResultData
     */
    @RequestMapping("/getTaskUsers")
    @Action(description = "获取某个流程实例上某个节点的配置执行人员")
    @ResponseBody
    public ResultData getTaskUsers(HttpServletRequest request){
        try {
            // 任务Id
            String taskId = request.getParameter("taskId");
            TaskEntity taskEntity = bpmService.getTask(taskId);
            // 所选择的节点Id
            String nodeId = RequestUtil.getString(request, "nodeId");
            if (StringUtil.isEmpty(nodeId)) {
                nodeId = taskEntity.getTaskDefinitionKey();
            }
            String procDefId = taskEntity.getProcessDefinitionId();
            String procInstId = taskEntity.getProcessInstanceId();
            Map<String, Object> vars = runtimeService.getVariables(taskEntity.getExecutionId());
            String startUserId = ContextUtil.getCurrentUserId();
            List<TaskExecutor> taskExecutorList = bpmNodeUserService.getExeUserIds(procDefId, procInstId, nodeId, startUserId, "", vars);
            return getResultDataSuccess("operation.success",taskExecutorList);
        }catch(Exception e){
            return getResultDataError("operation.failure",1,e.getMessage());
        }
    }

    /**
     * 获取任务明细
     * @param request request
     * @return ResultData
     */
    @RequestMapping("/miniDetail")
    @Action(description = "获取任务明细")
    @ResponseBody
    public ResultData getminiDetail(HttpServletRequest request){
        String taskId = RequestUtil.getString(request,"taskId");
        TaskEntity taskEntity = bpmService.getTask(taskId);
        if(taskEntity==null){
            return getResultDataError("task.query.failure");
        }
        //获取任务的候选人员
        Set<TaskExecutor> users = taskUserService.getCandidateExecutors(taskId);

        ProcessRun run  = processRunService.getByProcInstanceId(taskEntity.getProcessInstanceId());

        ActDefModel actDefModel = actDefModelService.getByProcDefId(taskEntity.getProcessDefinitionId());

        List<ProcessTask> taskList=bpmService.getTasks(taskEntity.getProcessInstanceId());

        //封装返回数据
        Map<String,Object> map = new HashMap<>(15);
        //流程事项名称
        map.put("subject",run.getSubject());
        //任务ID
        map.put("id",taskEntity.getId());
        //流程运行(RUNID)
        map.put("runId",run.getRunId());
        //任务名
        map.put("name",taskEntity.getName());
        //任务描述
        map.put("description",taskEntity.getDescription());
        // 单一执行人
        String assignee =   taskEntity.getAssignee();
        map.put("assignee",assignee);
        if(StringUtil.isNotEmpty(assignee)) {
            // 单一执行人的姓名
            map.put("assigneeName", sysUserDao.getById(taskEntity.getAssignee()).getFullName() );
        }else {
            //非单一任务执行人们
            map.put("assignees", taskUserService.getCandidateExecutors(taskId) );
        }
        //候选执行人
        map.put("users",users );
        //当前活动任务
        map.put("taskList",taskList);
        //创建时间
        map.put("createTime",taskEntity.getCreateTime());
        //到期时间
        map.put("dueDate",taskEntity.getDueDate());
        //流程定义名称
        map.put("actName",actDefModel.getName());
        //版本
        map.put("actVersion",actDefModel.getVersion());
        //流程定义描述
        map.put("actDescription",actDefModel.getDescription());

        return getResultDataSuccess("query.success",map);
    }

    /**
     * 更改任务执行人弹窗
     * @param request request
     * @param model 视图模型
     * @return 页面路径
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX+"/changeAssignee")
    @Action(ownermodel = SysAuditModelType.PROCESS_MANAGEMENT,description = "更改任务执行人弹窗")
    public String viewChangeAssignee(HttpServletRequest request,Model model){
        String taskId = RequestUtil.getString(request,"taskId");
        String dataPrivacyLevel = RequestUtil.getString(request,"dataPrivacyLevel");
        TaskEntity taskEntity = bpmService.getTask(taskId);
        if(taskEntity==null){
            return "workflow/task/taskNotExist";
        }
        Map<String, IMessageHandler> handlerMap = ServiceUtil.getHandlerMap();
        model.addAttribute("taskEntity",taskEntity)
                .addAttribute("dataPrivacyLevel",dataPrivacyLevel)
                .addAttribute("handlerMap",handlerMap);
        return getAutoView();
    }

    /**
     * 更改任务执行人
     * @param request request
     * @return ResultData
     */
    @RequestMapping("/changeAssignee")
    @Action(ownermodel = SysAuditModelType.PROCESS_MANAGEMENT,description = "更改任务执行人",detail = "更改任务${taskId}的执行人<#if fl>成功<#else>失败</#if>")
    @ResponseBody
    public ResultData changeAssignee(HttpServletRequest request){
        SysAuditThreadLocalHolder.putParamerter("fl", false);
        try{
            String taskId = RequestUtil.getString(request,"taskId");
            String userId = RequestUtil.getString(request,"userId");
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            String parentTaskId = task.getParentTaskId();
            if(null!=parentTaskId){
                Task parentTask = taskService.createTaskQuery().taskId(parentTaskId).singleResult();
                if (parentTask.getAssignee().equals(userId)) {
                    return getResultDataError("changeAssignee.error");
                }
            }
            String voteContent = RequestUtil.getString(request,"voteContent");
            String informType = RequestUtil.getString(request,"informType");
            String msg = processRunService.updateTaskAssignee(taskId,userId,voteContent,informType);
            SysAuditThreadLocalHolder.putParamerter("fl", true);
            return getResultDataSuccess(msg);
        }catch (Exception e){
            return getResultDataError("operation.failure",1,e.getMessage());
        }
    }


    /**
     * 沟通按钮，发送沟通意见到沟通人
     * @param request request
     * @return ResultData
     */
    @RequestMapping("/toStartCommunication")
    @Action(description = "发送沟通意见",detail = "发送沟通意见<#if fl>成功<#else>失败</#if>")
    @ResponseBody
    public ResultData toStartCommunication(HttpServletRequest request){
        SysAuditThreadLocalHolder.putParamerter("fl", false);
        String userIds = request.getParameter("userIds");
        if (StringUtil.isEmpty(userIds)) {
            return getResultDataError("task.toStart.user.null");
        }
        if(userIds.contains(ContextUtil.getCurrentUserId())){
            return getResultDataError("task.toStart.user.myself.failure");
        };
        try {
            String taskId = request.getParameter("taskId");
            String opinion = request.getParameter("opinion");
            String informType = RequestUtil.getString(request, "informType");
            // 保存意见
            TaskEntity taskEntity = bpmService.getTask(taskId);
            ProcessRun processRun = processRunService.getByProcInstanceId(taskEntity.getProcessInstanceId());

            processRunService.saveCommunication(taskEntity, opinion, informType, userIds, processRun.getSubject());
            ProcessCmd taskCmd = BpmUtil.getProcessCmd(request);
            processRunService.handlerFormData(taskCmd, processRun, taskEntity.getTaskDefinitionKey());

            String runId = processRun.getRunId();
            //流程操作日志
            String memo = "在:【" + processRun.getSubject() + "】,节点【" + taskEntity.getName() + "】,意见:" + opinion;
            bpmRunLogService.addRunLog(runId, BpmRunLog.OPERATOR_TYPE_ADDOPINION, memo);
            SysAuditThreadLocalHolder.putParamerter("fl", true);
            return getResultDataSuccess("task.toStart.communication.success");
        } catch (Exception e) {
            return getResultDataError("task.toStart.communication.failure",1,e.getMessage());
        }
    }

    /**
     * 反馈按钮，发送反馈意见到沟通发起人
     * @param request request
     * @param taskOpinion 意见
     * @return ResultData
     */
    @RequestMapping("/toStartFeedbackOpinions")
    @Action(description = "保存沟通反馈意见或流转意见",detail = "保存沟通反馈意见或流转意见<#if fl>成功<#else>失败</#if>")
    @ResponseBody
    public ResultData toStartFeedbackOpinions(HttpServletRequest request,TaskOpinion taskOpinion){
        String informType = RequestUtil.getString(request,"informType");
        boolean isAgree   = RequestUtil.getBoolean(request,"isAgree");

        ProcessCmd taskCmd = BpmUtil.getProcessCmd(request);
        //设置意见
        taskCmd.setVoteContent(taskOpinion.getOpinion());
        try {
            processRunService.handTransTo(taskOpinion,informType,isAgree,taskCmd);
            SysAuditThreadLocalHolder.putParamerter("fl", true);
            return getResultDataSuccess("task.toStart.feedback.success");
        } catch (Exception e) {
            SysAuditThreadLocalHolder.putParamerter("fl", false);
            return getResultDataError("task.toStart.feedback.failure",1,e.getMessage());
        }
    }

    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX+"/getRefList")
    @Action(description = "流程参考页面")
    public String viewGetRefList(HttpServletRequest request,Model model) {
        String modelId = RequestUtil.getString(request,"modelId");
        model.addAttribute("modelId",modelId);
        return getAutoView();
    }
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX+"/refList")
    @Action(description = "流程参考-我提交的流程页面")
    public String viewRefList(HttpServletRequest request,Model model) {
        String modelId = RequestUtil.getString(request,"modelId");
        model.addAttribute("modelId",modelId);
        return getAutoView();
    }
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX+"/refListApprove")
    @Action(description = "流程参考-抄送给我的流程页面")
    public String viewGetRefListApprove(HttpServletRequest request,Model model) {
        String modelId = RequestUtil.getString(request,"modelId");
        model.addAttribute("modelId",modelId);
        return getAutoView();
    }

    @RequestMapping("/getRefList")
    @Action(description = "查询我提交或抄送给我的流程列表数据",detail = "查询我提交或抄送给我的流程列表数据<#if fl>成功<#else>失败</#if>")
    @ResponseBody
    public ResultData getRefList(HttpServletRequest request) {
        try{
            String modelId = RequestUtil.getString(request,"modelId");
            //type==0，我提交的流程；type==1，抄送给我的流程
            Integer type  = RequestUtil.getInt(request,"int",0);
            //流程参考条数
            ActDefModel actDefModel = actDefModelService.getOneById(modelId);
            Integer instanceAmount = null;
            if(actDefModel!=null){
                instanceAmount = actDefModel.getInstanceAmount();
            }
            if(instanceAmount==null || instanceAmount <=0){
                instanceAmount = 5;
            }
            //获取当前用户
            String creatorId = ContextUtil.getCurrentUserId();
            List<ProcessRun> runList = processRunService.getRefList(modelId,creatorId,instanceAmount,type);
            SysAuditThreadLocalHolder.putParamerter("fl", true);
            return getResultDataSuccess("query.success", runList);
        }catch (Exception e){
            SysAuditThreadLocalHolder.putParamerter("fl", false);
            return getResultDataSuccess("query.failure");
        }

    }

    /**
     * 加签操作
     * @param request request
     * @return ResultData
     */
    @RequestMapping("/toStartTransTo")
    @Action(description = "加签操作",detail = "加签操作<#if fl>成功<#else>失败</#if>")
    @ResponseBody
    public ResultData toStartTransTo(HttpServletRequest request){
        String cmpIds = request.getParameter("cmpIds");
        if (StringUtil.isEmpty(cmpIds)) {
            SysAuditThreadLocalHolder.putParamerter("fl", false);
            return getResultDataError("please.enter.the.notifier");
        }
        try {
            //任务id
            String taskId = request.getParameter("taskId");
            //加签意见
            String opinion = request.getParameter("opinion");
            //通知类型
            String informType = RequestUtil.getString(request, "informType");
            //流转类型：1：非会签；2：会签
            String transType = request.getParameter("transType");
            //操作：1：返回；2：提交
            String action = request.getParameter("action");
            // 任务实体
            TaskEntity taskEntity = bpmService.getTask(taskId);
            ProcessRun processRun = processRunService.getByProcInstanceId(taskEntity.getProcessInstanceId());
            ProcessCmd taskCmd = BpmUtil.getProcessCmd(request);
            taskCmd.setVoteContent(opinion);
            processRunService.saveTransTo(taskEntity, opinion, informType, cmpIds, transType, action, processRun,taskCmd);
            SysAuditThreadLocalHolder.putParamerter("fl", true);
            return getResultDataSuccess("addTransTo.success");
        } catch (Exception e) {
            e.printStackTrace();
            SysAuditThreadLocalHolder.putParamerter("fl", false);
            return getResultDataError("addTransTo.failure");
        }
    }

    /**
     * 为url表单添加权限
     * @param request request
     * @return ResultData
     */
    @RequestMapping("/addPermissionToUrlForm")
    @ResponseBody
    @Action(description = "为url表单添加权限")
    public ResultData addPermissionToUrlForm(HttpServletRequest request) {
        String formKey = RequestUtil.getString(request, "formKey");
        String nodeId = RequestUtil.getString(request, "nodeId");
        String procDefId = RequestUtil.getString(request, "procDefId");
        String parentProcDefId = RequestUtil.getString(request, "parentProcDefId");
        PlatformType platformType = PlatformType.getEnumFromString(RequestUtil.getString(request, "platform", "PC"));
        try {
            String html = formRightsService.addPermissionToUrlForm(request, formKey, procDefId, nodeId, parentProcDefId, Integer.parseInt(platformType.toString()));
            return getResultDataSuccess("operation.success", html);
        } catch (IOException e) {
            e.printStackTrace();
            return getResultDataError("operation.failure");
        }
    }

}
